package leo.peersim.paxos;

import java.io.IOException;
import java.util.Vector;

import org.apache.log4j.Logger;

import leo.peersim.common.FileLoggerService;
import leo.peersim.common.IFSAutomaton;
import peersim.core.CommonState;
import peersim.core.Network;
import peersim.core.Node;

/**
 * 
 * @author leo
 * @version June 19, 2009
 */
public class PaxosSnooper {
	
	private Logger logger = Logger.getLogger(this.getClass().getName());
	
	private long minClientIssuingTime = Long.MAX_VALUE;
	private long maxClientIssuingTime = 0;
	private long generatedLoad;
	
	private long minLeaderExecutionTime = Long.MAX_VALUE;
	private long maxLeaderExecutionTime = 0;
	private long servedLoad;
	
	private long minRequestExecutionLatency = Long.MAX_VALUE;
	private long maxRequestExecutionLatency = 0;
	private long avgRequestExecutionLatency = 0;
	
	private long numberOfExecutedRequests = 0;
	private long numberOfPendingRequests = 0;
	
	private final int _protocolID;

	public PaxosSnooper(int protocolid) {
		this._protocolID = protocolid;
		try {
			this.analizza();
			this.printStats();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void printStats() {
		if(numberOfPendingRequests>0) {
			logger.fatal("There are pending requests: too much load!");
		}
		
		logger.info("load [op/s] generated: " + generatedLoad + ", served: " +servedLoad);
		logger.info("executed requests: " + numberOfExecutedRequests + ", leader execution latency [ms] avg:" + avgRequestExecutionLatency + ", min:" + minRequestExecutionLatency + ", max:" + maxRequestExecutionLatency);
	}
	
	private void analizza() throws IOException {
		
		FileLoggerService f = new FileLoggerService(this, "paxos");
		String s = "NodeId, clientIssuingTime, leaderExecutionTime, executionLatency";
		f.log(s);
		for(int i=0; i<Network.size(); i++) {
			
			Node n = Network.get(i);
			
			long nodeId = n.getID();
			
			IFSAutomaton aut = (IFSAutomaton) n.getProtocol(_protocolID);
			Vector<IClientRequest> c = aut.getClientRequests();
			
			for (IClientRequest req : c) {
				long issuingTime = req.getClientIssuingTime();
				long executionTime = req.getExecutionTime();
				long executionLatency = executionTime - issuingTime;
				
				s = nodeId + ", " + issuingTime + ", " + executionTime + ", " + executionLatency;
				f.log(s);
				
				
				
				if(executionTime>0) {
					minClientIssuingTime = Math.min(minClientIssuingTime, issuingTime);
					maxClientIssuingTime = Math.max(maxClientIssuingTime, issuingTime);
					
					minLeaderExecutionTime = Math.min(minLeaderExecutionTime, executionTime);
					maxLeaderExecutionTime = Math.max(maxLeaderExecutionTime, executionTime);
					
					minRequestExecutionLatency = Math.min(minRequestExecutionLatency, executionLatency);
					maxRequestExecutionLatency = Math.max(maxRequestExecutionLatency, executionLatency);
					
					avgRequestExecutionLatency += executionLatency;
					
					numberOfExecutedRequests++;
				} else {
					numberOfPendingRequests++;
				}
			}
		}
		f.closeStream();
		
		avgRequestExecutionLatency = (avgRequestExecutionLatency/numberOfExecutedRequests);
		
		generatedLoad = numberOfExecutedRequests*1000/(maxClientIssuingTime-minClientIssuingTime);
		servedLoad = numberOfExecutedRequests*1000/(maxLeaderExecutionTime-minLeaderExecutionTime);
	}
}
